﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using io = System.IO;
using System.IO;
using Xunit;
using Xunit.Extensions;

namespace MetaSharp.Transformation.Tests.Streams
{
    public class TextStreamTests
    {
        [Fact]
        public void EmptTextReportsEmptyStream()
        {
            var stream = FromString("");
            Assert.True(stream.IsEmpty);
        }

        [Fact]
        public void ATextStreamWithUnreadContentIsNotEmpty()
        {
            var stream = FromString("a");
            Assert.False(stream.IsEmpty);
        }

        [Fact]
        public void EmptyTextThrowsOnCurrent()
        {
            var stream = FromString("");
            Assert.Throws<InvalidOperationException>(() => stream.Current);
        }

        [Fact]
        public void CanGetNextOnNonEmptyString()
        {
            var stream = FromString("a");
            var next = stream.Next();
            Assert.Equal('a', next.Current);
        }

        [Fact]
        public void NextIsEmptyOnEndOfString()
        {
            var stream = FromString("a");
            var next = stream.Next();
            Assert.True(next.IsEmpty);
        }

        [Fact]
        public void NextIsNotEmptyOnLongerStream()
        {
            var stream = FromString("abc");
            var next = stream.Next();
            Assert.False(next.IsEmpty);
        }

        [Fact]
        public void CannotStepIntoTextStreams()
        {
            var stream = FromString("abc");
            Assert.Throws<NotSupportedException>(() => stream.Into());

            var a = Encoding.ASCII.EncodingName;
            var b = Encoding.BigEndianUnicode.EncodingName;
            var c = Encoding.Unicode.EncodingName;
            var d = Encoding.UTF32.EncodingName;
            var e = Encoding.UTF7.EncodingName;
            var f = Encoding.UTF8.EncodingName;
        }

        [Theory]
        [InlineData("US-ASCII")]
        [InlineData("Unicode (Big-Endian)")]
        [InlineData("Unicode")]
        [InlineData("Unicode (UTF-32)")]
        [InlineData("Unicode (UTF-7)")]
        [InlineData("Unicode (UTF-8)")]
        public void CanReadEncodedText(string name)
        {
            var encoding = GetEncoding(name);
            var stream = FromString("z", encoding);
            var next = stream.Next();
            Assert.Equal('z', next.Current);
        }

        private static Encoding GetEncoding(string name)
        {
            switch (name)
            {
                case "US-ASCII":
                    return Encoding.ASCII;
                case "Unicode (Big-Endian)":
                    return Encoding.BigEndianUnicode;
                case "Unicode":
                    return Encoding.Unicode;
                case "Unicode (UTF-32)":
                    return Encoding.UTF32;
                case "Unicode (UTF-7)":
                    return Encoding.UTF7;
                case "Unicode (UTF-8)":
                default:
                    return Encoding.UTF8;
            }
        }

        private static TextStream FromString(string content, Encoding encoding = null)
        {
            if (encoding == null)
                encoding = Encoding.UTF8;

            var preamble = encoding.GetPreamble();
            var bytes = encoding.GetBytes(content);
            var buffer = new byte[preamble.Length + bytes.Length];
            Array.ConstrainedCopy(preamble, 0, buffer, 0, preamble.Length);
            Array.ConstrainedCopy(bytes, 0, buffer, preamble.Length, bytes.Length);

            var stream = new MemoryStream(buffer);
            var reader = new StreamReader(stream, true);
            return new TextStream(reader);
        }
    }
}
